package simpledb;

import java.io.IOException;

/**
 * Inserts tuples read from the child operator into the tableId specified in the
 * constructor
 */
public class Insert extends Operator {

    private static final long serialVersionUID = 1L;

    private TransactionId transactionId;
    private OpIterator child;
    private int tableId;


    private int cnt;
    private TupleDesc tupleDesc;
    boolean isCalled;
    /**
     * Constructor.
     *
     * @param t
     *            The transaction running the insert.
     * @param child
     *            The child operator from which to read tuples to be inserted.
     * @param tableId
     *            The table in which to insert tuples.
     * @throws DbException
     *             if TupleDesc of child differs from table into which we are to
     *             insert.
     */
    public Insert(TransactionId t, OpIterator child, int tableId)
            throws DbException {
        // some code goes here
//        System.out.println("call class Insert");
        this.transactionId=t;
        this.child =child;
        this.tableId=tableId;

        tupleDesc=new TupleDesc(new Type[]{Type.INT_TYPE});
        cnt=-1;
        isCalled=false;
        if (!child.getTupleDesc().equals(
                Database.getCatalog().getTupleDesc(tableId))){
            throw new DbException("TupleDesc of child differs from table into which we are to insert");
        }
    }

    @Override
    public TupleDesc getTupleDesc() {
        // some code goes here
//        System.out.println("call Insert.getTupleDesc");
        return tupleDesc;
    }

    @Override
    public void open() throws DbException, TransactionAbortedException {
        // some code goes here
//        System.out.println("call Insert.open");
        super.open();
        child.open();
        cnt=0;
    }

    @Override
    public void close() {
        // some code goes here
//        System.out.println("call Insert.close");
        super.close();
        child.close();
        cnt=-1;
        isCalled=false;
    }

    @Override
    public void rewind() throws DbException, TransactionAbortedException {
        // some code goes here
//        System.out.println("call Insert.rewind");
        super.close();
        super.open();
        child.rewind();
        cnt=0;
        isCalled=false;
    }

    /**
     * Inserts tuples read from child into the tableId specified by the
     * constructor. It returns a one field tuple containing the number of
     * inserted records. Inserts should be passed through BufferPool. An
     * instances of BufferPool is available via Database.getBufferPool(). Note
     * that insert DOES NOT need check to see if a particular tuple is a
     * duplicate before inserting it.
     *
     * @return A 1-field tuple containing the number of inserted records, or
     *         null if called more than once.
     * @see Database#getBufferPool
     * @see BufferPool#insertTuple
     */
    @Override
    protected Tuple fetchNext() throws TransactionAbortedException, DbException {
        // some code goes here
//        System.out.println("call Insert.fetchNext");
        if (isCalled){
            return null;
        }
        isCalled=true;
        while (child.hasNext()){
            Tuple next=child.next();
            try {
                Database.getBufferPool().
                        insertTuple(transactionId,tableId,next);
                cnt++;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Tuple tuple=new Tuple(tupleDesc);
        tuple.setField(0,new IntField(cnt));
        return tuple;
    }

    @Override
    public OpIterator[] getChildren() {
        // some code goes here
        OpIterator[]opIterators={child};
        return opIterators;
    }

    @Override
    public void setChildren(OpIterator[] children) {
        // some code goes here
        child=children[0];
    }
}
